console.inspectEnable = true;
const WebApp = require('webapp');
const bodyParser = require("middleware").bodyParser;
const app = WebApp.createApp();
app.use(bodyParser.json());
app.use(WebApp.static('./public'));
const notify = require('notify');
const { GAS_DEFAULT_ALARM_VALUES } = require("./data/const");
const { devManager } = require('./data/device_manager');
const { sceneDB } = require('./data/lkv_db');

// 场景设备对象
let times = {};
let gas_window_scene = sceneDB.get('gas_window');

if (!gas_window_scene) {
	gas_window_scene = {
		devs: [],
	}
	updateSceneDB();
}

// socket.io server
const { initSocketIO } = require('./common/socket_server');
const socketIO = initSocketIO(app);
socketIO.on('connection', (socket) => {
	socket.on('init', (cb) => { // 应用初始化
		init();
		cb({
			// window_percent: gas_window_scene.settings.window_percent
		})
	});
	/* 添加场景设备 */
	socket.on('add-scene-device', (devid) => {
		addSceneDevice(devid, socket)
	});
	/* 删除场景设备 */
	socket.on('delete-scene-device', (devid) => {
		deleteSceneDevice(devid, socket)
	});
	socket.on('send-device-message', (params, cb) => {  // {devid: string, data: any}; 发送设备控制信息
		const { devid, data } = params;
		devManager.sendDeviceInfo(devid, data).then(() => {
			const dev = devManager.devMap.get(devid);
			if (dev) {
				const type = getDeviceType(dev)
				if (type && type !== 'window') {
					// 气体设备设置警告值
					gas_window_scene.devs = gas_window_scene.devs.map((item) => {
						if (item.devid === devid) {
							return {
								...item,
								settings: {
									alarm_value: data[type]
								}
							}
						}
						return item
					})
					updateSceneDB()
					socketIO.emit('alarm', { devid, value: data[type] });
				}
			}
		}).catch((err) => {
			emitError(err || '操作失败！')
		})
	});
})

// 初始化应用前端数据
function init() {
	emitDevices();
	initScene();
}

// 初始化场景
function initScene() {
	if (!gas_window_scene) {
		gas_window_scene = {
			devs: [],
		}
		updateSceneDB();
	}
	for (const { devid, settings: { alarm_value, window_percent } } of gas_window_scene.devs) {
		const dev = devManager.devMap.get(devid);
		if (!dev || !dev.join) {
			// 说明设备被删除 或者 不在线
			continue;
		}
		if (!devManager.controllerMap.has(devid)) {
			generateDevController(devid).then(() => {
				const type = getDeviceType(dev);
				if (!type) return
				if (type === 'window') {
					// 开窗器
					socketIO.emit('join', { ...dev, real_value: window_percent });
					devManager.sendDeviceInfo(dev.devid, { method: 'set', window_percent: window_percent || 0 })
				} else {
					// 气体
					socketIO.emit('join', { ...dev, real_value: 0, alarm_value });
					devManager.sendDeviceInfo(devid, { method: 'get', obj: [type] }).catch(() => {
						console.error(`Failed to get ${type} real-time value.`);
					});
				}
			}).catch((err) => {
				console.error('generateDevController error.');
			})
		} else {
			// 其他用户进入应用后同步设备状态
			const type = getDeviceType(dev);
			if (!type) return
			if (type === 'window') {
				// 开窗器
				socketIO.emit('join', { ...dev, real_value: window_percent });
			} else {
				// 气体
				socketIO.emit('join', { ...dev, real_value: 0, alarm_value });
				devManager.sendDeviceInfo(devid, { method: 'get', obj: [type] }).catch(() => {
					console.error(`Failed to get ${type} real-time value.`);
				});
			}
		}
	}
}

// 同步设备列表
function emitDevices() {
	socketIO.emit('devices', [...devManager.devMap.values()]);
}

// 成功提示
function emitSuccess(msg) {
	socketIO.emit('success', msg);
}

// 错误提示
function emitError(msg) {
	socketIO.emit('error', msg);
}

// 添加场景设备
function addSceneDevice(devid, socket) {
	const dev = devManager.devMap.get(devid);
	if (!dev) {
		return socketIO.to(socket.id).emit('error', '设备不存在，请检查重试！')
	}
	generateDevController(devid).then(() => {
		const type = getDeviceType(dev);
		if (!type) {
			return socketIO.to(socket.id).emit('error', '设备类型或型号错误！');;
		}
		if (type === 'window') { // 窗户
			gas_window_scene.devs.push({ devid, settings: { window_percent: 0 } });
			updateSceneDB();
			socketIO.emit('join', { ...dev, real_value: 0 });
			// 左移重置
			devManager.sendDeviceInfo(devid, { method: 'set', window: 'left' }).catch(() => {
				console.error(`Failed to set window.`);
			});
			return
		}
		// 气体设备
		gas_window_scene.devs.push({ devid, settings: { alarm_value: GAS_DEFAULT_ALARM_VALUES[type] } });
		updateSceneDB();
		socketIO.emit('join', { ...dev, real_value: 0, alarm_value: GAS_DEFAULT_ALARM_VALUES[type] });
		// 获取气体最新实时值
		devManager.sendDeviceInfo(devid, { method: 'get', obj: [type] }).catch(() => {
			socketIO.to(socket.id).emit('error', `获取${dev.alias}设备实时值失败！`)
		});
		// 重置气体设定警告值
		const data = { method: 'set' };
		data[type] = GAS_DEFAULT_ALARM_VALUES[type];
		devManager.sendDeviceInfo(devid, data).catch(() => {
			socketIO.to(socket.id).emit('error', `初始化${dev.alias}设备警告值失败！`)
		});
	}).catch((err) => {
		socketIO.to(socket.id).emit('error', err)
	})
}

// 删除场景设备
function deleteSceneDevice(devid, socket) {
	gas_window_scene.devs = gas_window_scene.devs.filter((item) => {
		return item.devid !== devid
	})
	updateSceneDB();
	devManager.deleteController(devid);
	clearInterval(times[devid]);
	times[devid] = undefined;
	socketIO.emit('delete', devManager.devMap.get(devid));
}

devManager.on('join', (dev) => {
	emitDevices();
	const scene_dev = gas_window_scene.devs.find((item) => { return item.devid === dev.devid });
	if (scene_dev) {
		generateDevController(dev.devid).then((controller) => {
			const type = getDeviceType(dev);
			if (!type) return
			if (type === 'window') {
				// 开窗器
				socketIO.emit('join', { ...dev, real_value: scene_dev.settings.window_percent });
				devManager.sendDeviceInfo(dev.devid, { method: 'set', window_percent: scene_dev.settings.window_percent || 0 })
			} else {
				// 气体
				socketIO.emit('join', { ...dev, real_value: 0, alarm_value: scene_dev.settings.alarm_value });
				devManager.sendDeviceInfo(dev.devid, { method: 'get', obj: [type] }).catch(() => {
					console.error(`Failed to get ${type} real-time value.`);
				});
			}
		}).catch((err) => {
			console.error(err)
		})
	}
});

devManager.on('lost', (dev) => {
	emitDevices();
	if (isSceneDev(dev.devid)) {
		clearInterval(times[dev.devid]);
		times[dev.devid] = undefined;
		socketIO.emit('lost', dev);
	}
});

devManager.on('error', (data) => {
	emitError(data)
})

// 构建设备控制对象
function generateDevController(devid) {
	return new Promise((resolve, reject) => {
		const dev = devManager.devMap.get(devid);
		if (!dev) {
			return reject('no device.')
		}
		devManager.generateController(devid).then((controller) => {
			const type = getDeviceType(dev);
			if (type && type !== 'window') {
				// 气体
				clearInterval(times[devid]);
				times[devid] = undefined;
				times[devid] = setInterval(() => {
					devManager.sendDeviceInfo(devid, { method: 'get', obj: [type] }).catch(() => {
						console.error(`Failed to get ${type} real-time value.`);
					});
				}, 3000);
			}
			controller.on('message', ({ data }) => {
				// 开窗器需要记录当前位置	
				if (type === 'window') {
					socketIO.emit('message', { devid, data: data.window_percent })
					gas_window_scene.devs = gas_window_scene.devs.map((item) => {
						if (item.devid === devid) {
							return {
								...item,
								settings: {
									window_percent: data['window_percent']
								}
							}
						}
						return item
					})
					updateSceneDB();
				} else {
					socketIO.emit('message', { devid, data: data[type] }); // 气体
					if (GAS_DEFAULT_ALARM_VALUES[type] < data[type]) {
						// 气体超标 找到窗户设备
						const window_dev = gas_window_scene.devs.find((item) => {
							const d = devManager.devMap.get(item.devid);
							if (d && getDeviceType(d) === 'window') {
								return true
							}
							return false
						});
						if (window_dev) {
							devManager.sendDeviceInfo(window_dev.devid, { method: 'set', window: 'right' }).catch(() => {
								console.error(`Failed to open window value.`);
							});
						}
					}
				}
			});
			resolve(controller);
		}).catch(() => {
			reject(`no permission.`);
			emitError(`应用缺少控制${dev.alias}的权限！`)
		})
	})
}

// 更新猫眼场景数据库
function updateSceneDB() {
	sceneDB.set('gas_window', gas_window_scene);
}

// 是否是场景设备
function isSceneDev(devid) {
	return gas_window_scene.devs.findIndex((item) => (item.devid === devid)) >= 0
}

// 获取符合条件的设备类型
function getDeviceType(dev) {
	const { report: { type, model } } = dev || {};
	if (type === 'device.window' && model === 'IDWINDOW01B') {
		return 'window'
	}
	if (type === 'gas.co' && model === 'IDCO01B') {
		return 'co'
	}
	if (type === 'gas.ch2o' && model === 'IDCH2O01B') {
		return 'ch2o'
	}
	if (type === 'gas.c2h5oh' && model === 'IDC2H5OH01B') {
		return 'c2h5oh'
	}
	if (type === 'gas.tvoc' && model === 'IDTVOC01B') {
		return 'tvoc'
	}
	if (type === 'gas.ch4' && model === 'IDCH401B') {
		return 'ch4'
	}
}


app.start();
require('iosched').forever();
